/**
 * 	 DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *   @author Colin Redmond
 *   Copyright (C) 2011 Colin Redmond
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

package com.cred.industries.platform.dialog {
	
	import com.cred.industries.platform.view.component.DialogBackingAndTitle
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.utils.getDefinitionByName;
	
	import mx.core.FlexGlobals;
	import mx.managers.ISystemManager;
	import mx.managers.PopUpManager;
	
	import spark.components.Button;
	import spark.components.Label;
	import spark.components.SkinnablePopUpContainer;

	/**
	 * We use a single multpurpose dialog that can
	 * have 0-3 buttons with customizeable body and title text
	 * There can only be one up at a time
	 * 
	 * @author Colin Redmond
	 * Copyright TBA Digital 2011
	 */
	public final class DialogManager extends SkinnablePopUpContainer {
		
		private static var sInstance:DialogManager;
		public static var VERTICAL_LAYOUT_MODE:String = "vertical";
		public static var HORIZONTAL_LAYOUT_MODE:String = "horizontal";
		
		public static var CLOSE_BUTTON_EVENT:String = "CLOSE_BUTTON_EVENT";
		public static var OK_BUTTON_EVENT:String = "OK_BUTTON_EVENT";
		public static var YES_BUTTON_EVENT:String = "YES_BUTTON_EVENT";
		public static var NO_BUTTON_EVENT:String = "NO_BUTTON_EVENT";
		public static var CANCEL_BUTTON_EVENT:String = "CANCEL_BUTTON_EVENT";
		
		[SkinPart(required="false")]  public var backing:DialogBackingAndTitle;
		[SkinPart(required="false")]  public var body:Label;
		[SkinPart(required="false")]  public var button1:Button;
		[SkinPart(required="false")]  public var button2:Button;
		[SkinPart(required="false")]  public var button3:Button;
		
		private var mTitle:String = "";
		private var mBody:String = "";
		
		private var numButtons:int;
		private var button1String:String = "";
		private var button2String:String = "";
		private var button3String:String = "";
		private var button1Event:String = "";
		private var button2Event:String = "";
		private var button3Event:String = "";

		private var showClose:Boolean = false;
		private var mParent:Sprite;
		private var mode:String = "";
		private var mIsSelfClosing:Boolean = false;
		
		public function DialogManager() { }
		
		/**
		 * return the static instance. Only exists when visible
		 * 
		 */
		public static function get():DialogManager {
			return sInstance;
		}
		
		/**
		 * Function to get the root in the swf file so we can attach to it
		 * if needed, we then add the dialog to that
		 */
		public static function getRoot():Sprite {
			var root:Sprite = null;
			//if we havent specified the parent get it from the system manager
			var sm:ISystemManager = ISystemManager(FlexGlobals.topLevelApplication.systemManager);
			// no types so no dependencies
			var mp:Object = sm.getImplementation("mx.managers.IMarshallPlanSystemManager");
			if (mp && mp.useSWFBridge())
				root = Sprite(sm.getSandboxRoot());
			else
				root = Sprite(FlexGlobals.topLevelApplication);
			
			return root;
		}
		
		/**
		 * generic function to call to create a dialog. 
		 * Will create and show the dialog according to the parameters
		 * You specify the name of the events you want back. so if you say button1 has a name "cancel" and 
		 * the event is "CANCEL" you would add a listener to "CANCEL"
		 * @param buttonXString the name that will appear on the button
		 * @param buttonXEvent the event that will be thrown when button X is pressed
		 * @param modal if it should block input from anything behind itself
		 * @param isSelfClosing the dialog will close itself after any button click
		 * @param mode (not implemented, reserved for having diffrent modes on the dialog)
		 * @param skinClass you can customize the skin for the dialog so it can look anyway you wish
		 * @param parent who owns this dialog if not provided it will get the root and it will be the owner
		 */
		public static function showDialog( title:String, body:String, numButtons:int, showClose:Boolean
							  , button1String:String, button1Event:String
							  , button2String:String = "", button2Event:String = ""
							  , button3String:String = "", button3Event:String = ""
							  , modal:Boolean = true
							  , isSelfClosing:Boolean = false
							  , mode:String = "horizontal"
							  , skinClass:String = "com.view.dialog.CustomDialog"
							  , parent:Sprite = null):void {
			
			if(sInstance != null) {
				
				trace("already a dialog up " + sInstance.backing.title.text + ", this will clober the existing one");
				return;
			}
			sInstance = new DialogManager();
			sInstance.mParent = parent;
			sInstance.mode = mode;
			sInstance.mTitle = title;
			sInstance.mBody = body;
			
			sInstance.numButtons = numButtons;
			sInstance.button1String = button1String;
			sInstance.button2String = button2String;
			sInstance.button3String = button3String;
			sInstance.button1Event = button1Event;
			sInstance.button2Event = button2Event;
			sInstance.button3Event = button3Event;
			sInstance.showClose = showClose;
			sInstance.mIsSelfClosing = isSelfClosing;
						
			//if we havent specified the parent get it from the system manager
			if (!sInstance.mParent)	{
				
				sInstance.mParent = getRoot();
			}
		
		
			//we need to get the skin class definition, for this to work the class must be created in 
			//com.model.SwcPreLoader, Unfortuantly any skins you use must be created there.
			var skinAsset:Class = getDefinitionByName(skinClass) as Class;
			//use the skin class to set the skin style
			sInstance.setStyle("skinClass", skinAsset);
			trace("test");
			sInstance.invalidateSkinState();
			sInstance.open(sInstance.mParent, modal);
			
			//we need to listen to the resize event so we can center the popups 
			sInstance.systemManager.stage.addEventListener(Event.RESIZE, sInstance.onResize, false, 0, true);
			PopUpManager.centerPopUp(sInstance);
		}
		
		/**
		 * specific implementation to show a simple dialog with one button.
		 * All you need to provide is the title and body. By default it will use one button with "OK"
		 * and the event "OK_BUTTON_EVENT" to listen for
		 */
		public static function alert(title:String, body:String
									 , button1String:String = "OK", button1Event:String = "OK_BUTTON_EVENT"
									 , numButtons:int = 1
									 , mode:String = "horizontal", modal:Boolean = true, showClose:Boolean = false
									 , button2String:String = "", button2Event:String = ""
									 , button3String:String = "", button3Event:String = ""
									 , parent:Sprite = null
									 , skinClass:String = "com.view.dialog.CustomDialog"
									 , isSelfClosing:Boolean = true):void {
			
			showDialog(title, body, numButtons, showClose, button1String, button1Event, button2String, button2Event, button3String, button3Event, modal, isSelfClosing, mode, skinClass, parent);
		}
		
		/**
		 * specific implementation to show a simple dialog with an ok and cancel buttons
		 * All you need to provide is the title and body. By default it will use two  button with "OK" and "Cancel"
		 * and the event "OK_BUTTON_EVENT" and "CANCEL_BUTTON_EVENT" to listen for 
		 */
		public static function showOkCancel(title:String, body:String
									 , button1String:String = "OK", button1Event:String = "OK_BUTTON_EVENT"
									 , button2String:String = "CANCEL", button2Event:String = "CANCEL_BUTTON_EVENT"
									 , numButtons:int = 2
									 , mode:String = "horizontal", modal:Boolean = true, showClose:Boolean = false
									 , button3String:String = "", button3Event:String = ""
									 , parent:Sprite = null
  									 , skinClass:String = "com.view.dialog.CustomDialog"
	   							     , isSelfClosing:Boolean = false):void 	{
			
			showDialog(title, body, numButtons, showClose, button1String, button1Event, button2String, button2Event, button3String, button3Event, modal, isSelfClosing, mode, skinClass, parent);
		}
	
		/**
		 * Since this uses a skin we need to setup the parts of the skin as they are added
		 */
		override protected function partAdded(partName:String, instance:Object) : void {
			//set up the buttons as they are added
			//we want to add the listeners and the setup the text
			switch(numButtons) {
				case 1: {
					
					if(instance == button2)	{
						
						instance.addEventListener(MouseEvent.CLICK, buttonHandler, false, 0, true);
						(instance as Button).label = button1String;
					} else if(instance == button1 || instance == button3) {
						
						instance.visible = false;
					}
				}
				break;
				
				case 2: {
					
					if(instance == button1) {
						instance.addEventListener(MouseEvent.CLICK, buttonHandler, false, 0, true);
						(instance as Button).label = button1String;
					} else if(instance == button3) {
						instance.addEventListener(MouseEvent.CLICK, buttonHandler, false, 0, true);
						(instance as Button).label = button2String;
					} else if(instance == button2) {
						instance.visible = false;
					}
				}
				break;
				
				case 3: {
					if(instance == button1) {
						instance.addEventListener(MouseEvent.CLICK, buttonHandler, false, 0, true);
						(instance as Button).label = button1String;
					} else if(instance == button2) {
						instance.addEventListener(MouseEvent.CLICK, buttonHandler, false, 0, true);
						(instance as Button).label = button2String;
					} else if(instance == button3) {
						instance.addEventListener(MouseEvent.CLICK, buttonHandler, false, 0, true);
						(instance as Button).label = button3String;
					}
				}
				break;
			}
			
			//setup the close button when added
			if(instance == backing) {
				
				if(showClose) {
					
					backing.closeButton.visible = true;
					backing.closeButton.addEventListener(MouseEvent.CLICK, closeHandler, false, 0, true);
				} else {
					backing.closeButton.visible = false;
				}
				backing.title.text = mTitle; 
			}
						
			if(instance == body) {
				(instance as Label).text = mBody; 
			}
		}
		
		/**
		 * override the default close so we can remove the resize listener
		 */
		override public function close(commit:Boolean = false, data:* = undefined):void {
			
			sInstance.systemManager.stage.removeEventListener(Event.RESIZE, sInstance.onResize, false);
			sInstance = null;
			super.close(commit, data);
		}
				
		private function closeHandler(event:MouseEvent):void {
			if(mIsSelfClosing)
				this.close();
			dispatchEvent(new Event(CLOSE_BUTTON_EVENT));
		}
		
		private function buttonHandler(event:MouseEvent):void {
			
			if(mIsSelfClosing)
				this.close();			
			
			switch(numButtons) {
				case 1: {
					
					dispatchEvent(new Event(button1Event));
				}
				break;
				
				case 2: {
					
					if(event.target == button1)	{
						
						dispatchEvent(new Event(button1Event));
					} else  if(event.target == button3)	{
						
						dispatchEvent(new Event(button2Event));
					}
				}
				break;
				
				case 3:
				{
					if(event.target == button1)	{
						
						dispatchEvent(new Event(button1Event));
					} else if(event.target == button2) {
						
						dispatchEvent(new Event(button2Event));
					} else if(event.target == button3) {
						
						dispatchEvent(new Event(button3Event));
					}
				}
			}
		}
		
		override protected function getCurrentSkinState():String {
			
			var state:String = super.getCurrentSkinState();
			if (isOpen)
				return mode+state;
			else 
				return state;
		}
		
		/**
		 * when the stage is resized we need to center the popup.
		 */
		private function onResize(event:Event):void {
			
			if(sInstance) {
				
				PopUpManager.centerPopUp(sInstance);
			}
		}
	}
}